package com.bruce.starts.demo.commonerror.transaction;

import com.bruce.starts.demo.commonerror.dao.UserRepository;
import com.bruce.starts.demo.commonerror.entity.UserEntity;
import com.bruce.starts.demo.commonerror.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;

@Service
public class TransactionExecuteDemo {
    @Autowired
    private UserService userService;
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private PlatformTransactionManager transactionManager;
    private static ThreadPoolExecutor threadPoolExecutor;

    @PostConstruct
    public void iniitThreadPool() {
        //初始化线程池
        threadPoolExecutor = new ThreadPoolExecutor(
                20,
                20,
                60,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(20),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardPolicy()
        );
    }

    public void serviceTest() throws InterruptedException {
        //子线程等待主线程通知
        CountDownLatch mainMonitor = new CountDownLatch(1);
        CountDownLatch childMonitor = new CountDownLatch(5);
        AtomicReference<Boolean> isError = new AtomicReference<>(false);
        AtomicLong id = new AtomicLong();
        List<Future> futureList = new ArrayList<>();
        try {
            for (int i = 0; i < 5; i++) {
                 Future<UserEntity> future = threadPoolExecutor.submit(() -> {
                     DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
                     defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
                     TransactionStatus transactionStatus = transactionManager.getTransaction(defaultTransactionDefinition);
                     UserEntity userEntity = new UserEntity();
                     try {
                         userEntity.setId(id.incrementAndGet());
                         userEntity.setAge(31);
                         userEntity.setName("bruce");
                         userEntity.setNickName("更改的昵称"+ThreadLocalRandom.current().nextInt(20));
                         System.out.println("开始更新用户:"+userEntity.toString());
                         userRepository.save(userEntity);
                         if(ThreadLocalRandom.current().nextInt(3)==2){
                             System.out.println("模拟异常");
                             throw new Exception("模拟异常");
                         }
                     } catch (Exception e) {
                         isError.set(true);
                         System.out.println("更新用户【"+userEntity.getName()+"】出现异常："+e.getMessage());
                     }
                     childMonitor.countDown();
                     System.out.println(Thread.currentThread().getName() + "：准备就绪,等待其他线程结果,判断是否事务提交");
                     try {
                         childMonitor.await();
                         if(isError.get()){
                             System.out.println(Thread.currentThread().getName()+"回滚事务");
                             transactionManager.rollback(transactionStatus);
                         }else{
                             System.out.println(Thread.currentThread().getName()+"提交事务");
                             transactionManager.commit(transactionStatus);
                         }
                     }catch (Exception e){
                         e.printStackTrace();
                         System.out.println("事务提交出现异常");
                     }
                     return userEntity;
                 });
                futureList.add(future);
                Thread.sleep(100);
            }
            futureList.forEach(future2 -> {
                try {
                    System.out.println("已更新的用户"+future2.get());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        } catch (Exception e) {
            System.out.println("出现异常----------------------" + e.getMessage());
        }
        childMonitor.await();
        System.out.println("执行完毕");
    }

    private static void serviceTest(int i) {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (i == 4) {
            throw new RuntimeException("出现异常");
        }
    }
}
